// Copyright 2017 Proyectos y Sistemas de Mantenimiento SL (eProsima).
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ------------------------------------------------------------------
// Modification history:
// feature: Support static xml filter by participant name
// feature: add qos incompatible check, and add system test case
// ------------------------------------------------------------------

#include <xmlparser/XMLParserPart.h>
#include <xmlparser/XMLParserCommonPart.h>
#include <xmlparser/XMLTreePart.h>
#include <xmlparser/XMLProfileManagerPart.h>
#include <tinyxml2.h>
#include <cstdlib>
#include <iostream>
#include <string>
#include <unordered_map>

#include <elog/ApiConsumer.hpp>
#include <elog/StdoutConsumer.hpp>
#include <elog/StdoutErrConsumer.hpp>
#include <elog/FileConsumer.hpp>
#include "xmlparser/transport_descriptors/shared_queue_transport_descriptor.h"
#include "xmlparser/qos/XMLQosPolicies.hpp"

namespace vbsutil {
namespace xmlparser {

std::string XMLErrorToString(tinyxml2::XMLError error) {
    using namespace tinyxml2;
    switch (error) {
        case XML_SUCCESS:
            return "XML_SUCCESS";
        case XML_NO_ATTRIBUTE:
            return "XML_NO_ATTRIBUTE";
        case XML_WRONG_ATTRIBUTE_TYPE:
            return "XML_WRONG_ATTRIBUTE_TYPE";
        case XML_ERROR_FILE_NOT_FOUND:
            return "XML_ERROR_FILE_NOT_FOUND";
        case XML_ERROR_FILE_COULD_NOT_BE_OPENED:
            return "XML_ERROR_FILE_COULD_NOT_BE_OPENED";
        case XML_ERROR_FILE_READ_ERROR:
            return "XML_ERROR_FILE_READ_ERROR";
        case XML_ERROR_PARSING_ELEMENT:
            return "XML_ERROR_PARSING_ELEMENT";
        case XML_ERROR_PARSING_ATTRIBUTE:
            return "XML_ERROR_PARSING_ATTRIBUTE";
        case XML_ERROR_PARSING_TEXT:
            return "XML_ERROR_PARSING_TEXT";
        case XML_ERROR_PARSING_CDATA:
            return "XML_ERROR_PARSING_CDATA";
        case XML_ERROR_PARSING_COMMENT:
            return "XML_ERROR_PARSING_COMMENT";
        case XML_ERROR_PARSING_DECLARATION:
            return "XML_ERROR_PARSING_DECLARATION";
        case XML_ERROR_PARSING_UNKNOWN:
            return "XML_ERROR_PARSING_UNKNOWN";
        case XML_ERROR_EMPTY_DOCUMENT:
            return "XML_ERROR_EMPTY_DOCUMENT";
        case XML_ERROR_MISMATCHED_ELEMENT:
            return "XML_ERROR_MISMATCHED_ELEMENT";
        case XML_ERROR_PARSING:
            return "XML_ERROR_PARSING";
        case XML_CAN_NOT_CONVERT_TEXT:
            return "XML_CAN_NOT_CONVERT_TEXT";
        case XML_NO_TEXT_NODE:
            return "XML_NO_TEXT_NODE";
        case XML_ELEMENT_DEPTH_EXCEEDED:
            return "XML_ELEMENT_DEPTH_EXCEEDED";
        default:
            return "UNKNOWN_XML_ERROR";
    }
}

std::vector<std::string> XMLParserpart::parsed_profiles_;
std::vector<std::unordered_multimap<std::string, std::string>> XMLParserpart::parsed_consumers_;
#if HAVE_SECURITY
std::atomic<bool> XMLParserpart::enable_security_ = true;
std::atomic<bool> XMLParserpart::enforce_security_ = false;

bool XMLParserpart::is_security_enabled() {
    return enable_security_.load();
}

void XMLParserpart::set_security(bool enable) {
    enable_security_.store(enable);
}

bool XMLParserpart::is_enforcing() {
    return enforce_security_.load();
}

void XMLParserpart::set_enforce(bool enable) {
    set_security(true);
    enforce_security_.store(enable);
}
#endif

// 使用unordered_multimap计数每个元素名和文本的出现
void CountElements(tinyxml2::XMLElement* element, std::unordered_multimap<std::string, std::string>& elementsMap) {
    for (tinyxml2::XMLElement* child = element->FirstChildElement(); child != nullptr;
         child = child->NextSiblingElement()) {
        const char* text = child->GetText() ? child->GetText() : "";
        elementsMap.emplace(child->Name(), text);
        CountElements(child, elementsMap);
    }
}

bool XMLParserpart::isConsumerDuplicate(tinyxml2::XMLElement* consumer) {
    std::unordered_multimap<std::string, std::string> elementsTemp;
    CountElements(consumer, elementsTemp);
    for (const auto& pair : XMLParserpart::parsed_consumers_) {
        if (pair == elementsTemp) {
            return true;
        }
    }
    XMLParserpart::parsed_consumers_.push_back(std::move(elementsTemp));
    return false;
}

XMLP_ret XMLParserpart::loadDefaultXMLFile(vbsutil::xmlparser::up_base_node_t& root) {
    return loadXML(xmlString::DEFAULT_ERTPS_PROFILES, root);
}

XMLP_ret XMLParserpart::loadXML(const std::string& filename, up_base_node_t& root) {
    if (filename.empty()) {
        elogError(XMLPARSER, RetCode_t::RETCODE_BAD_PARAMETER, "Error loading XML file, filename empty");
        return XMLP_ret::XML_ERROR;
    }

    tinyxml2::XMLDocument xmlDoc;
    tinyxml2::XMLError ret = xmlDoc.LoadFile(filename.c_str());
    if (tinyxml2::XMLError::XML_SUCCESS != ret) {
        if (filename != std::string(xmlString::DEFAULT_ERTPS_PROFILES)) {
            elogError(XMLPARSER, RetCode_t::RETCODE_BAD_PARAMETER,
                      "Error opening '" << filename << "' with return code:" << XMLErrorToString(ret));
        }
        return XMLP_ret::XML_ERROR;
    }

    logDebug(XMLPARSER, "File '" << filename << "' opened successfully");
    return parseXML(xmlDoc, root);
}

XMLP_ret XMLParserpart::loadXML(const char* data, size_t length, up_base_node_t& root) {
    tinyxml2::XMLDocument xmlDoc;
    if (tinyxml2::XMLError::XML_SUCCESS != xmlDoc.Parse(data, length)) {
        elogError(XMLPARSER, RetCode_t::RETCODE_NO_DATA, "Error parsing XML buffer");
        return XMLP_ret::XML_ERROR;
    }
    return parseXML(xmlDoc, root);
}

XMLP_ret XMLParserpart::loadXML(tinyxml2::XMLDocument& xmlDoc, up_base_node_t& root) {
    return parseXML(xmlDoc, root);
}

XMLP_ret XMLParserpart::parseXML(tinyxml2::XMLDocument& xmlDoc, up_base_node_t& root) {
    XMLP_ret ret = XMLP_ret::XML_OK;
    tinyxml2::XMLElement* node = xmlDoc.FirstChildElement();
    if ((node == nullptr) || (node->Value() == nullptr)) {
        elogError(XMLPARSER, RetCode_t::RETCODE_BAD_PARAMETER, "xml config is empty.");
        return XMLP_ret::XML_ERROR;
    }

    const char* vbs_tag = node->Value();
    if (strcmp(vbs_tag, xmlString::VBS) == 0) {
        root.reset(new BaseNode {NodeType::VBS});
        node = node->FirstChildElement();
        if (strcmp(node->Value(), xmlString::RPC) == 0) {
            node = node->NextSiblingElement();
        }
    }

    const char* root_tag = node->Value();
    if (strcmp(root_tag, xmlString::DDS) == 0) {
        root.reset(new BaseNode {NodeType::DDS});
        node = node->FirstChildElement();
    } else if (strcmp(root_tag, xmlString::TYPES) == 0) {
        root.reset(new BaseNode {NodeType::TYPES});
    } else if (strcmp(root_tag, xmlString::PROFILES) == 0) {
        root.reset(new BaseNode {NodeType::PROFILES});
    } else {
        elogError(XMLPARSER, RetCode_t::RETCODE_BAD_PARAMETER, "xml root tag '" << root_tag << "' invalid.");
        return XMLP_ret::XML_ERROR;
    }

    const char* tag = nullptr;
    while ((node != nullptr) && (ret == XMLP_ret::XML_OK)) {
        if ((tag = node->Value()) != nullptr) {
            if (strcmp(tag, xmlString::PROFILES) == 0) {
                up_base_node_t profiles_node = up_base_node_t {new BaseNode {NodeType::PROFILES}};
                if (XMLP_ret::XML_OK == (ret = XMLParserpart::parseProfiles(node, *profiles_node))) {
                    root->addChild(std::move(profiles_node));
                } else {
                    elogError(XMLPARSER, RetCode_t::RETCODE_ERROR, "parseProfiles error");
                    return XMLP_ret::XML_ERROR;
                }
            } else if (strcmp(tag, xmlString::LOG) == 0) {
                vbsutil::xmlparser::up_base_node_t log_node = vbsutil::xmlparser::up_base_node_t {
                    new vbsutil::xmlparser::BaseNode {vbsutil::xmlparser::NodeType::LOG}};
                if (XMLP_ret::XML_OK == (ret = parseLogConfig(node))) {
                    root->addChild(std::move(log_node));
                } else {
                    elogError(XMLPARSER, RetCode_t::RETCODE_ERROR, "parseLogConfig error");
                    return XMLP_ret::XML_ERROR;
                }
            } else if (strcmp(tag, xmlString::TYPES) == 0 || strcmp(tag, xmlString::LIBRARY_SETTINGS) == 0 ||
                       strcmp(tag, xmlString::RPC) == 0 || strcmp(tag, xmlString::AGENT) == 0) {
                node = node->NextSiblingElement();
                continue;  // this part execute in evbs
            } else if (strcmp(tag, xmlString::BASEXML) == 0) {
                std::string name = getAttributeName(xmlString::NAME, node);
                // 默认base和当前xml为同一路径，如果没有配置路径，则取子xml name中的路径信息进行拼接
                if ((name.find_last_of("/\\") == std::string::npos) && (XMLProfileManagerPart::currentXmlPath != "")) {
                    name = XMLProfileManagerPart::currentXmlPath + name;
                }
                logDebug(XMLPARSER, "basexml name is:'" << name << "' ");
                ret = XMLProfileManagerPart::loadXMLFile(name);
#if HAVE_SECURITY
            } else if (strcmp(tag, xmlString::SECURITY) == 0) {
                const char* text = node->GetText();
                if (text != nullptr) {
                    std::string security;
                    security.resize(strlen(text));
                    // convert to lowercase
                    std::transform(text, text + security.size(), security.begin(),
                                   [](unsigned char c) { return std::tolower(c); });
                    if (security == "false") {
                        set_security(false);
                    } else if (security == "true") {
                        set_security(true);
                    } else if (security == "enforcing") {
                        set_enforce(true);
                    } else if (security == "permissive") {
                        set_enforce(false);
                    }
                }
#endif
            } else {
                elogError(XMLPARSER, RetCode_t::RETCODE_BAD_PARAMETER, "xmlpart, Not expected tag: '" << tag << "'");
                ret = XMLP_ret::XML_ERROR;
            }
        }
        node = node->NextSiblingElement();
    }
    return ret;
}

XMLP_ret XMLParserpart::parseXMLTransportsProf(tinyxml2::XMLElement* p_root) {
    /*
          <xs:complexType name="TransportDescriptorListType">
              <xs:sequence>
                  <xs:element name="transport_descriptor" type="rtpsTransportDescriptorType"/>
              </xs:sequence>
          </xs:complexType>
       */

    XMLP_ret ret = XMLP_ret::XML_OK;
    tinyxml2::XMLElement* p_element = p_root->FirstChildElement(xmlString::TRANSPORT_DESCRIPTOR);
    while (p_element != nullptr) {
        ret = parseXMLDSFTransportData(p_element);
        if (ret != XMLP_ret::XML_OK) {
            elogError(XMLPARSER, RetCode_t::RETCODE_ERROR, "Error parsing transports");
            return ret;
        }
        p_element = p_element->NextSiblingElement(xmlString::TRANSPORT_DESCRIPTOR);
    }
    return ret;
}

XMLP_ret XMLParserpart::parseXMLDSFTransportData(tinyxml2::XMLElement* p_root) {
    XMLP_ret ret = XMLP_ret::XML_OK;
    std::string sId = "";
    sp_transport_t pDescriptor = nullptr;

    tinyxml2::XMLElement* p_aux0 = nullptr;
    p_aux0 = p_root->FirstChildElement(xmlString::TRANSPORT_ID);
    if (nullptr == p_aux0) {
        elogError(XMLPARSER, RetCode_t::RETCODE_ERROR, "Not found '" << xmlString::TRANSPORT_ID << "' attribute");
        return XMLP_ret::XML_ERROR;
    } else {
        if (p_aux0->GetText() != nullptr) {
            sId = p_aux0->GetText();
        } else {
            elogError(XMLPARSER, RetCode_t::RETCODE_ERROR,
                      "'" << xmlString::TRANSPORT_ID << "' attribute cannot be empty");
            return XMLP_ret::XML_ERROR;
        }
    }

    p_aux0 = p_root->FirstChildElement(xmlString::TYPE);
    if (nullptr == p_aux0) {
        elogError(XMLPARSER, RetCode_t::RETCODE_ERROR, "Not found '" << xmlString::TYPE << "' attribute");
        return XMLP_ret::XML_ERROR;
    } else {
        std::string sType;
        if (p_aux0->GetText() != nullptr) {
            sType = p_aux0->GetText();
        } else {
            elogError(XMLPARSER, RetCode_t::RETCODE_ERROR, "'" << xmlString::TYPE << "' attribute cannot be empty");
            return XMLP_ret::XML_ERROR;
        }
        if (sType == ((xmlString::SHARED_SHM_QUEUE == nullptr) ? "" : xmlString::SHARED_SHM_QUEUE)) {
            pDescriptor = std::make_shared<SharedQueueTransportDescriptorPart>();
            ret = parseXMLSharedQueueTransportData(p_root, pDescriptor);
            if (ret != XMLP_ret::XML_OK) {
                return ret;
            }
            XMLProfileManagerPart::insertTransportById(sId, std::move(pDescriptor));
        }
    }
    return ret;
}

XMLP_ret XMLParserpart::parseXMLSharedQueueTransportData(tinyxml2::XMLElement* p_root, sp_transport_t p_transport) {
    /*
          <xs:complexType name="rtpsTransportDescriptorType">
              <xs:all minOccurs="0">
                  <xs:element name="wake_up_mode" type="uint32Type" minOccurs="0" maxOccurs="1"/>
                  <xs:element name="queue_size" type="uint32Type" minOccurs="0" maxOccurs="1"/>
                  </xs:all>
          </xs:complexType>
       */

    XMLP_ret ret = XMLP_ret::XML_OK;
    std::shared_ptr<SharedQueueTransportDescriptorPart> transport_descriptor =
        std::dynamic_pointer_cast<SharedQueueTransportDescriptorPart>(p_transport);
    if (transport_descriptor != nullptr) {
        tinyxml2::XMLElement* p_aux0 = nullptr;
        const char* name = nullptr;
        for (p_aux0 = p_root->FirstChildElement(); p_aux0 != nullptr; p_aux0 = p_aux0->NextSiblingElement()) {
            name = p_aux0->Name();
            if (strcmp(name, xmlString::QUEUE_WAKE_UP_MODE) == 0) {
                std::string str;
                if (XMLP_ret::XML_OK != getXMLString(p_aux0, &str, 0)) {
                    return XMLP_ret::XML_ERROR;
                }
                QueueWakeUp wake_up = PTHREAD_CONDITION_WAKE_UP;
                if (str.empty()) {
                    wake_up = PTHREAD_CONDITION_WAKE_UP;
                } else {
                    wake_up = StrToQueueWakeUp(str);
                }
                transport_descriptor->SetWakeUpMode(wake_up);
            } else if (strcmp(name, xmlString::QUEUE_SIZE) == 0) {
                std::string str2;
                if (XMLP_ret::XML_OK != getXMLString(p_aux0, &str2, 0)) {
                    return XMLP_ret::XML_ERROR;
                }
                try {
                    size_t pos;
                    uint64_t res = std::stoull(str2, &pos);
                    if ((res > std::numeric_limits<uint32_t>::max()) || (pos < str2.size())) {
                        elogError(XMLPARSER, RetCode_t::RETCODE_ERROR,
                                  "queue_size's value: " << str2 << " is invalid conversion error");
                        return XMLP_ret::XML_ERROR;
                    }
                    transport_descriptor->SetQueueSize(static_cast<uint32_t>(res));
                } catch (const std::exception& e) {
                    elogError(XMLPARSER, RetCode_t::RETCODE_ERROR,
                              "queue_size's value: " << str2 << " is invalid,exception e:" << e.what());
                    return XMLP_ret::XML_ERROR;
                }
            } else if (strcmp(name, xmlString::TRANSPORT_ID) == 0 || strcmp(name, xmlString::TYPE) == 0) {
                // Parsed Outside of this method
            } else {
                elogError(XMLPARSER, RetCode_t::RETCODE_ERROR,
                          "Invalid element found into 'rtpsTransportDescriptorType'. Name: " << name);
                return XMLP_ret::XML_ERROR;
            }
        }
    } else {
        elogError(XMLPARSER, RetCode_t::RETCODE_ERROR, "Error parsing SharedQueue Transport data");
        ret = XMLP_ret::XML_ERROR;
    }

    return ret;
}

XMLP_ret XMLParserpart::parseProfiles(tinyxml2::XMLElement* p_root, BaseNode& profilesNode) {

    auto name = getAttributeName(xmlString::NAME, p_root);
    auto base_name = getAttributeName(xmlString::BASE_NAME, p_root);
    auto is_default_profile = getAttributeName(xmlString::DEFAULT_PROF, p_root);
    if (!name.empty()) {
        if (std::find(parsed_profiles_.begin(), parsed_profiles_.end(), name) != parsed_profiles_.end()) {
            elogError(XMLPARSER, RetCode_t::RETCODE_ILLEGAL_OPERATION, "profiles name '" << name << "' already exist.");
            return XMLP_ret::XML_ERROR;
        }
        if (!base_name.empty()) {
            (void)XMLProfileManagerPart::getInheritanceCombinationBaseInfo(xmlString::BASE_NAME);  // profile继承模式
            if (generateProfileByBaseProfile(name, base_name) != XMLP_ret::XML_OK) {
                return XMLP_ret::XML_ERROR;
            }
        }
    }
    tinyxml2::XMLElement* p_profile = p_root->FirstChildElement();
    const char* tag = nullptr;
    bool parseOk = true;
    XMLP_ret ret = XMLP_ret::XML_OK;
    while (nullptr != p_profile) {
        if (nullptr != (tag = p_profile->Value())) {
            if (strcmp(tag, xmlString::TYPES) == 0 || strcmp(tag, xmlString::LIBRARY_SETTINGS) == 0) {
                p_profile = p_profile->NextSiblingElement();
                continue;  // this part execute in evbs
            }
            if (XMLProfileManagerPart::getInheritanceCombinationBaseInfo(tag)) {  // profile组合模式
                if (name.empty()) {
                    continue;
                }
                parseOk &= getXMLSnippetProfileAttributes(p_profile, name) == XMLP_ret::XML_OK;
            } else if (strcmp(tag, xmlString::TRANSPORT_DESCRIPTORS) == 0) {
                parseOk &= (parseXMLTransportsProf(p_profile) == XMLP_ret::XML_OK);
            } else if (strcmp(tag, xmlString::PARTICIPANT) == 0) {
                parseOk &= parseXMLParticipantProf(p_profile, profilesNode, name, base_name) == XMLP_ret::XML_OK;
            } else if ((strcmp(tag, xmlString::PUBLISHER) == 0) || (strcmp(tag, xmlString::DATA_WRITER) == 0)) {
                parseOk &= parseXMLPublisherProf(p_profile, profilesNode, name, base_name) == XMLP_ret::XML_OK;
            } else if ((strcmp(tag, xmlString::SUBSCRIBER) == 0) || (strcmp(tag, xmlString::DATA_READER) == 0)) {
                parseOk &= parseXMLSubscriberProf(p_profile, profilesNode, name, base_name) == XMLP_ret::XML_OK;
            } else if (strcmp(tag, xmlString::TOPIC) == 0) {
                parseOk &= parseXMLTopicData(p_profile, profilesNode) == XMLP_ret::XML_OK;
            } else {
                parseOk = false;
                elogError(XMLPARSER, RetCode_t::RETCODE_BAD_PARAMETER, "Not expected tag: '" << tag << "'");
            }
        }
        if (!parseOk) {
            elogError(XMLPARSER, RetCode_t::RETCODE_ERROR, "Error parsing profile's tag ");
            ret = XMLP_ret::XML_ERROR;
        }
        p_profile = p_profile->NextSiblingElement();
    }

    if (!name.empty()) {
        if (ret == XMLP_ret::XML_OK) {
            parsed_profiles_.push_back(name);
        }
        if (is_default_profile == "true") {
            XMLProfileManagerPart::setDefaultProfile(name);
        }
    }

    return ret;
}

XMLP_ret XMLParserpart::parseLogConfig(tinyxml2::XMLElement* p_root) {
    using vbsutil::elog::Log;

    XMLP_ret ret = XMLP_ret::XML_OK;
    tinyxml2::XMLElement* p_aux0 = p_root->FirstChildElement(xmlString::LOG);
    if (p_aux0 == nullptr) {
        p_aux0 = p_root;
    }

    tinyxml2::XMLElement* p_element = p_aux0->FirstChildElement();
    const char* tag = nullptr;
    while (nullptr != p_element) {
        if (nullptr != (tag = p_element->Value())) {
            if (p_element->NoChildren()) {
                elogError(XMLPARSER, RetCode_t::RETCODE_BAD_PARAMETER,
                          "name is Self-closing tag, please cheack name label");
                return XMLP_ret::XML_ERROR;
            }
            if (strcmp(tag, xmlString::USE_DEFAULT) == 0) {
                bool use_default = true;
                std::string auxBool = p_element->GetText();
                if (std::strcmp(auxBool.c_str(), "FALSE") == 0) {
                    use_default = false;
                }
                if (!use_default) {
                    Log::ClearConsumers();
                }
            } else if (strcmp(tag, xmlString::LEVEL) == 0) {
                static uint32_t log_level_by_xml = Log::Kind::Error;
                std::string auxLevel = p_element->GetText();
                if (std::strcmp(auxLevel.c_str(), xmlString::XML_ERROR) == 0) {
                    log_level_by_xml |= Log::Kind::Error;
                } else if (std::strcmp(auxLevel.c_str(), xmlString::XML_WARNING) == 0) {
                    log_level_by_xml |= Log::Kind::Warning;
                } else if (std::strcmp(auxLevel.c_str(), xmlString::XML_INFO) == 0) {
                    log_level_by_xml |= Log::Kind::Info;
                } else if (std::strcmp(auxLevel.c_str(), xmlString::XML_EVENT) == 0) {
                    log_level_by_xml |= Log::Kind::Event;
                } else if (std::strcmp(auxLevel.c_str(), xmlString::DEBUG_) == 0) {
                    log_level_by_xml |= Log::Kind::Debug;
                } else if (auxLevel.find(xmlString::XML_INFO) != std::string::npos &&
                           auxLevel.find(xmlString::XML_EVENT) != std::string::npos) {
                    log_level_by_xml |= Log::Kind::Info | Log::Kind::Event;
                } else if (auxLevel.find(xmlString::XML_WARNING) != std::string::npos &&
                           auxLevel.find(xmlString::XML_EVENT) != std::string::npos) {
                    log_level_by_xml |= Log::Kind::Warning | Log::Kind::Event;
                } else if (auxLevel.find(xmlString::XML_ERROR) != std::string::npos &&
                           auxLevel.find(xmlString::XML_EVENT) != std::string::npos) {
                    log_level_by_xml |= Log::Kind::Error | Log::Kind::Event;
                } else if (auxLevel.find(xmlString::DEBUG_) != std::string::npos &&
                           auxLevel.find(xmlString::XML_EVENT) != std::string::npos) {
                    log_level_by_xml |= Log::Kind::Debug | Log::Kind::Event;
                } else {
                    elogError(XMLPARSER, RetCode_t::RETCODE_BAD_PARAMETER,
                              "Not expected level: '" << auxLevel.c_str() << "'");
                    ret = XMLP_ret::XML_ERROR;
                }
                if (ret != XMLP_ret::XML_ERROR) {
                    Log::SetVerbosity(log_level_by_xml);
                }
            } else if (std::strcmp(tag, xmlString::LATENCY_THRESHOLD) == 0) {
                uint64_t latencyThreshold = 0;
                if (XMLP_ret::XML_OK ==
                    vbsutil::xmlparser::XMLParserpart::getXMLUint64(p_element, &latencyThreshold, 1U)) {
                    logDebug(XMLPARSER, "set latency_threshold:" << latencyThreshold);
                    Log::SetLatencyThreshold(static_cast<float>(latencyThreshold));
                } else {
                    elogError(XMLPARSER, RetCode_t::RETCODE_BAD_PARAMETER,
                              "latency_threshold value is wrong, so we use default");
                }
            } else if (std::strcmp(tag, xmlString::PERIOD_METRICS_INTERVAL) == 0) {
                uint64_t periodMetricsInterval = 0;
                if (XMLP_ret::XML_OK ==
                    vbsutil::xmlparser::XMLParserpart::getXMLUint64(p_element, &periodMetricsInterval, 1U)) {
                    logDebug(XMLPARSER, "set period_metrics_interval:" << periodMetricsInterval);
                    Log::SetInterval(periodMetricsInterval);
                } else {
                    elogError(XMLPARSER, RetCode_t::RETCODE_BAD_PARAMETER,
                              "period_metrics_interval value is wrong, so we use default");
                }
            } else if (std::strcmp(tag, xmlString::REPORT_WITH_PKTCOUNT) == 0) {
                uint64_t reportWithPktCount = 0;
                if (XMLP_ret::XML_OK ==
                    vbsutil::xmlparser::XMLParserpart::getXMLUint64(p_element, &reportWithPktCount, 1U)) {
                    logDebug(XMLPARSER, "set reportWithPktCount:" << reportWithPktCount);
                    Log::SetReportWithPktcount(reportWithPktCount);
                } else {
                    elogError(XMLPARSER, RetCode_t::RETCODE_BAD_PARAMETER,
                              "reportWithPktCount value is wrong, so we use default");
                }
            } else if (std::strcmp(tag, xmlString::PKTLOSSRATE_THRESHOLD) == 0) {
                float rateThreshold = 0.0f;
                if (XMLP_ret::XML_OK == vbsutil::xmlparser::XMLParserpart::getXMLFloat(p_element, &rateThreshold, 1U)) {
                    logDebug(XMLPARSER, "set packetlossrate_threshold:" << rateThreshold);
                    Log::SetLossrateThreshold(rateThreshold);
                } else {
                    elogError(XMLPARSER, RetCode_t::RETCODE_BAD_PARAMETER,
                              "packetlossrate_threshold value is wrong, so we use default");
                }
            } else if (std::strcmp(tag, xmlString::THROUGHPUT_THRESHOLD) == 0) {
                float throughputThreshold = 0.0f;
                if (XMLP_ret::XML_OK ==
                    vbsutil::xmlparser::XMLParserpart::getXMLFloat(p_element, &throughputThreshold, 1U)) {
                    logDebug(XMLPARSER, "set throughput_threshold:" << throughputThreshold);
                    Log::SetThroughputThreshold(throughputThreshold);
                } else {
                    elogError(XMLPARSER, RetCode_t::RETCODE_BAD_PARAMETER,
                              "throughput_threshold value is wrong, so we use default");
                }
            } else if (strcmp(tag, xmlString::CONSUMER) == 0) {
                // 判断当前consumer的内容是否和已存储的一致
                if (isConsumerDuplicate(p_element)) {
                    logDebug(XMLPARSER, "consumer is duplicated, please check xml consumer");
                } else {
                    ret = parseXMLConsumer(*p_element);
                    if (ret == XMLP_ret::XML_ERROR) {
                        return ret;
                    }
                }
            } else if (strcmp(tag, xmlString::MSG_TRACE_MASK) == 0) {
                uint32_t msg_trace_mask = 0;
                if (vbsutil::xmlparser::XMLParserpart::getXMLUint(p_element, &msg_trace_mask, 0U) == XMLP_ret::XML_OK) {
                    vbsutil::elog::Log::setMsgTraceMask(msg_trace_mask);
                }
            } else if (strcmp(tag, xmlString::MSG_BRIEF_LIMIT) == 0) {
                uint32_t msg_record_limit = 0;
                if (vbsutil::xmlparser::XMLParserpart::getXMLUint(p_element, &msg_record_limit, 0U) ==
                    XMLP_ret::XML_OK) {
                    vbsutil::elog::Log::setMsgBriefLimit(msg_record_limit);
                }
            } else if (strcmp(tag, xmlString::LOG_PERIOD) == 0) {
                uint32_t log_period;
                if (vbsutil::xmlparser::XMLParserpart::getXMLUint(p_element, &log_period, 0U) == XMLP_ret::XML_OK) {
                    vbsutil::elog::Log::setLogPeriod(log_period);
                }
            } else if (strcmp(tag, xmlString::MSG_TOPIC_FILTER) == 0) {
                std::string topics = p_element->GetText();
                std::stringstream ss(topics);
                std::string topicName;
                while (std::getline(ss, topicName, '|')) {
                    vbsutil::elog::Log::addMsgTopicFilter(topicName);
                }
            } else if (strcmp(tag, xmlString::MSG_BRIEF_MODE) == 0) {
                uint16_t outputMode = 0;
                if (XMLP_ret::XML_OK == getXMLUint(p_element, &outputMode, 1U)) {
                    logDebug(XMLPARSER, "set MSG_BRIEF_MODE:" << outputMode);
                    Log::setMsgBriefOutputMode(outputMode);
                } else {
                    elogError(XMLPARSER, RetCode_t::RETCODE_BAD_PARAMETER,
                              "period_metrics_interval value is wrong, so we use default");
                }
            } else {
                elogError(XMLPARSER, RetCode_t::RETCODE_BAD_PARAMETER, "Not expected tag: '" << tag << "'");
                ret = XMLP_ret::XML_ERROR;
            }
        }
        p_element = p_element->NextSiblingElement();
    }
    return ret;
}

XMLP_ret XMLParserpart::parseXMLConsumer(tinyxml2::XMLElement& consumer) {
    using vbsutil::elog::ApiConsumer;
    using vbsutil::elog::FileConsumer;
    using vbsutil::elog::Log;
    using vbsutil::elog::LogConsumer;
    using vbsutil::elog::StdoutConsumer;
    using vbsutil::elog::StdoutErrConsumer;

    XMLP_ret ret = XMLP_ret::XML_OK;
    tinyxml2::XMLElement* p_element = consumer.FirstChildElement(xmlString::CLASS);
    if (p_element == nullptr || p_element->NoChildren()) {
        elogError(XMLPARSER, RetCode_t::RETCODE_BAD_PARAMETER,
                  "class is null or class is Self-closing tag, please cheack label");
        return XMLP_ret::XML_ERROR;
    }
    if (p_element != nullptr) {
        std::string classStr = p_element->GetText();
        if (std::strcmp(classStr.c_str(), "StdoutConsumer") == 0) {
            Log::RegisterConsumer(std::unique_ptr<LogConsumer>(new StdoutConsumer));
        } else if (std::strcmp(classStr.c_str(), "ApiConsumer") == 0) {
            std::string categoryFilter = "";

            tinyxml2::XMLElement* property = consumer.FirstChildElement(xmlString::PROPERTY);
            if (nullptr != property) {
                tinyxml2::XMLElement* p_auxName = nullptr;
                tinyxml2::XMLElement* p_auxValue = nullptr;
                while (nullptr != property) {
                    // name - stringType
                    if (nullptr != (p_auxName = property->FirstChildElement(xmlString::NAME))) {
                        if (p_auxName->NoChildren()) {
                            elogError(XMLPARSER, RetCode_t::RETCODE_BAD_PARAMETER,
                                      "name is Self-closing tag, please cheack name label");
                            return XMLP_ret::XML_ERROR;
                        }
                        std::string s = p_auxName->GetText();

                        if (std::strcmp(s.c_str(), "category_filter") == 0) {
                            if ((nullptr != (p_auxValue = property->FirstChildElement(xmlString::VALUE))) &&
                                (nullptr != p_auxValue->GetText())) {
                                categoryFilter = p_auxValue->GetText();
                            } else {
                                elogError(XMLPARSER, RetCode_t::RETCODE_BAD_PARAMETER,
                                          "category_filter value cannot be found for " << classStr << " log consumer.");
                                ret = XMLP_ret::XML_NOK;
                            }
                        } else {
                            elogError(XMLPARSER, RetCode_t::RETCODE_BAD_PARAMETER,
                                      "Unknown property " << s << " in " << classStr << " log consumer.");
                            ret = XMLP_ret::XML_NOK;
                        }
                    }
                    property = property->NextSiblingElement(xmlString::PROPERTY);
                }

                auto& log_consumer = Log::GetApiConsumer();
                assert(log_consumer != nullptr);
                log_consumer->SetCategoryFilter(std::move(categoryFilter));
            }
        } else if (std::strcmp(classStr.c_str(), "StdoutErrConsumer") == 0) {
            /* Register a StdoutErrConsumer */

            // Get first property
            tinyxml2::XMLElement* property = consumer.FirstChildElement(xmlString::PROPERTY);
            if (nullptr == property) {
                // If no properties are specified, create the consumer with default values
                Log::RegisterConsumer(std::unique_ptr<LogConsumer>(new StdoutErrConsumer));
            } else {
                // Only one property is supported. Its name is `stderr_threshold`, and its value is
                // a log kind specified as a string in the form `Log::Kind::<Kind>`.
                tinyxml2::XMLElement* p_auxName = nullptr;     // Property name
                tinyxml2::XMLElement* p_auxValue = nullptr;    // Property value
                uint8_t stderr_threshold_property_count = 0U;  // Occurrences count. Only one is allowed

                // Get default threshold
                Log::Kind threshold = StdoutErrConsumer::STDERR_THRESHOLD_DEFAULT;

                // Iterate over the properties
                while (nullptr != property) {
                    if (nullptr != (p_auxName = property->FirstChildElement(xmlString::NAME))) {
                        // Get property name
                        if (p_auxName->NoChildren()) {
                            elogError(XMLPARSER, RetCode_t::RETCODE_BAD_PARAMETER,
                                      "name is Self-closing tag, please cheack name label");
                            return XMLP_ret::XML_ERROR;
                        }
                        std::string s = p_auxName->GetText();

                        if (std::strcmp(s.c_str(), "stderr_threshold") == 0) {
                            /* Property is a `stderr_threshold` */

                            // Update occurrence count and check how many encountered. Only the
                            // first one applies, the rest are ignored.
                            stderr_threshold_property_count++;
                            if (stderr_threshold_property_count > 1) {
                                // Continue with the next property if `stderr_threshold` had been
                                // already specified.
                                elogError(XMLPARSER, RetCode_t::RETCODE_ERROR,
                                          classStr << " only supports one occurrence of 'stderr_threshold'."
                                                   << " Only the first one is applied.");
                                property = property->NextSiblingElement(xmlString::PROPERTY);
                                ret = XMLP_ret::XML_NOK;
                                continue;
                            }

                            // Get the property value. It should be a Log::Kind.
                            if (nullptr != (p_auxValue = property->FirstChildElement(xmlString::VALUE))) {
                                // Get property value and use it to set the threshold.
                                std::string threshold_str = p_auxValue->GetText();
                                if (std::strcmp(threshold_str.c_str(), "Log::Kind::Error") == 0) {
                                    threshold = Log::Kind::Error;
                                } else if (std::strcmp(threshold_str.c_str(), "Log::Kind::Warning") == 0) {
                                    threshold = Log::Kind::Warning;
                                } else if (std::strcmp(threshold_str.c_str(), "Log::Kind::Info") == 0) {
                                    threshold = Log::Kind::Info;
                                } else {
                                    elogError(XMLPARSER, RetCode_t::RETCODE_BAD_PARAMETER,
                                              "Unkown Log::Kind '" << threshold_str << "'. Using default threshold.");
                                    ret = XMLP_ret::XML_NOK;
                                }
                            }
                        } else {
                            elogError(XMLPARSER, RetCode_t::RETCODE_BAD_PARAMETER,
                                      "Unkown property value '" << s << "' in " << classStr << " log consumer");
                            ret = XMLP_ret::XML_NOK;
                        }
                    }
                    // Continue with the next property
                    property = property->NextSiblingElement(xmlString::PROPERTY);
                }

                // Create consumer with the specified `stderr_threshold` and register it.
                StdoutErrConsumer* log_consumer = new StdoutErrConsumer;
                log_consumer->stderr_threshold(threshold);
                Log::RegisterConsumer(std::unique_ptr<LogConsumer>(log_consumer));
            }
        } else if (std::strcmp(classStr.c_str(), "FileConsumer") == 0) {
            std::string outputFile = "output.log";
            bool append = false;
            uint64_t maxFileSize = FileConsumer::sc_maxFileSize;
            std::string categoryFilter = "";
            vbsutil::elog::FileConsumer::SaveMode savemode = vbsutil::elog::FileConsumer::SaveMode::BACKUP;
            uint32_t rotateFileCout = vbsutil::elog::FileConsumer::rotateFileCout_;  // default
            bool uploadFormat = false;
            std::string nodeName = "";

            tinyxml2::XMLElement* property = consumer.FirstChildElement(xmlString::PROPERTY);
            if (nullptr == property) {
                Log::RegisterConsumer(std::unique_ptr<LogConsumer>(new FileConsumer));
            } else {
                tinyxml2::XMLElement* p_auxName = nullptr;
                tinyxml2::XMLElement* p_auxValue = nullptr;
                while (nullptr != property) {
                    // name - stringType
                    if (nullptr != (p_auxName = property->FirstChildElement(xmlString::NAME))) {
                        if (p_auxName->NoChildren()) {
                            elogError(XMLPARSER, RetCode_t::RETCODE_BAD_PARAMETER,
                                      "name is Self-closing tag, please cheack name label");
                            return XMLP_ret::XML_ERROR;
                        }
                        std::string s = p_auxName->GetText();

                        if (std::strcmp(s.c_str(), "filename") == 0) {
                            if ((nullptr != (p_auxValue = property->FirstChildElement(xmlString::VALUE))) &&
                                (nullptr != p_auxValue->GetText())) {
                                outputFile = p_auxValue->GetText();
                            } else {
                                elogError(XMLPARSER, RetCode_t::RETCODE_BAD_PARAMETER,
                                          "Filename value cannot be found for " << classStr << " log consumer.");
                                ret = XMLP_ret::XML_NOK;
                            }
                        } else if (std::strcmp(s.c_str(), "append") == 0) {
                            if ((nullptr != (p_auxValue = property->FirstChildElement(xmlString::VALUE))) &&
                                (nullptr != p_auxValue->GetText())) {
                                std::string auxBool = p_auxValue->GetText();
                                if (std::strcmp(auxBool.c_str(), "TRUE") == 0) {
                                    append = true;
                                }
                            } else {
                                elogError(XMLPARSER, RetCode_t::RETCODE_BAD_PARAMETER,
                                          "Append value cannot be found for " << classStr << " log consumer.");
                                ret = XMLP_ret::XML_NOK;
                            }
                        } else if (std::strcmp(s.c_str(), "max_file_size") == 0) {
                            if ((nullptr != (p_auxValue = property->FirstChildElement(xmlString::VALUE))) &&
                                (nullptr != p_auxValue->GetText())) {
                                uint8_t ident = 1;
                                if (XMLP_ret::XML_OK !=
                                    vbsutil::xmlparser::XMLParserpart::getXMLUint64(p_auxValue, &maxFileSize, ident)) {
                                    elogError(XMLPARSER, RetCode_t::RETCODE_BAD_PARAMETER,
                                              "max_file_size value is not unsigned long type, so we use default value "
                                                  << FileConsumer::sc_maxFileSize << " instead.");
                                    maxFileSize = FileConsumer::sc_maxFileSize;
                                }
                            }
                        } else if (std::strcmp(s.c_str(), "category_filter") == 0) {
                            if ((nullptr != (p_auxValue = property->FirstChildElement(xmlString::VALUE))) &&
                                (nullptr != p_auxValue->GetText())) {
                                categoryFilter = p_auxValue->GetText();
                            } else {
                                elogError(XMLPARSER, RetCode_t::RETCODE_BAD_PARAMETER,
                                          "category_filter value cannot be found for " << classStr << " log consumer.");
                                ret = XMLP_ret::XML_NOK;
                            }
                        } else if (std::strcmp(s.c_str(), "savemode") == 0) {
                            if ((nullptr != (p_auxValue = property->FirstChildElement(xmlString::VALUE))) &&
                                (nullptr != p_auxValue->GetText())) {
                                std::string text = p_auxValue->GetText();
                                if (text.find("rotate") != std::string::npos) {
                                    savemode = vbsutil::elog::FileConsumer::SaveMode::ROTATE;
                                    size_t pos = text.find(":");
                                    if (pos != std::string::npos) {
                                        std::string numStr = text.substr(pos + 1);
                                        rotateFileCout = std::stoi(numStr);
                                    }
                                }

                            } else {
                                elogError(XMLPARSER, RetCode_t::RETCODE_BAD_PARAMETER,
                                          "savemode value cannot be found for " << classStr << " log consumer.");
                                ret = XMLP_ret::XML_NOK;
                            }
                        } else if (std::strcmp(s.c_str(), "uploadformat") == 0) {
                            if ((nullptr != (p_auxValue = property->FirstChildElement(xmlString::VALUE))) &&
                                (nullptr != p_auxValue->GetText())) {
                                std::string auxBool = p_auxValue->GetText();
                                if (std::strcmp(auxBool.c_str(), "TRUE") == 0) {
                                    uploadFormat = true;
                                }
                            } else {
                                elogError(XMLPARSER, RetCode_t::RETCODE_BAD_PARAMETER,
                                          "uploadformat value cannot be found for " << classStr << " log consumer.");
                                ret = XMLP_ret::XML_NOK;
                            }
                        } else if (std::strcmp(s.c_str(), "nodename") == 0) {
                            if ((nullptr != (p_auxValue = property->FirstChildElement(xmlString::VALUE))) &&
                                (nullptr != p_auxValue->GetText())) {
                                nodeName = p_auxValue->GetText();
                            } else {
                                elogError(XMLPARSER, RetCode_t::RETCODE_BAD_PARAMETER,
                                          "nodename value cannot be found for " << classStr << " log consumer.");
                                ret = XMLP_ret::XML_NOK;
                            }
                        } else {
                            elogError(XMLPARSER, RetCode_t::RETCODE_BAD_PARAMETER,
                                      "Unknown property " << s << " in " << classStr << " log consumer.");
                            ret = XMLP_ret::XML_NOK;
                        }
                    }
                    property = property->NextSiblingElement(xmlString::PROPERTY);
                }

                FileConsumer* log_consumer = new FileConsumer(outputFile, append, maxFileSize, uploadFormat, nodeName);
                log_consumer->SetSaveMode(savemode);
                log_consumer->SetRotateNum(rotateFileCout);
                log_consumer->SetCategoryFilter(std::move(categoryFilter));
                Log::RegisterConsumer(std::unique_ptr<LogConsumer>(log_consumer));
            }
        } else if (std::strcmp(classStr.c_str(), "OnlineConsumer") == 0) {

        } else {
            elogError(XMLPARSER, RetCode_t::RETCODE_BAD_PARAMETER, "Unknown log consumer class: " << classStr);
            ret = XMLP_ret::XML_ERROR;
        }
    }

    return ret;
}

XMLP_ret XMLParserpart::parseXMLParticipantProf(tinyxml2::XMLElement* p_root, BaseNode& rootNode,
                                                const std::string& profile_lib_name,
                                                const std::string& profiles_base_name) {
    XMLP_ret ret = XMLP_ret::XML_OK;
    up_participant_t participant_atts {new ParticipantAttributes};
    up_node_participant_t participant_node {
        new node_participant_t {NodeType::PARTICIPANT, std::move(participant_atts)}};

    std::vector<bool> set_flags(ParticipantConfigKind::PART_CONFIG_END);
    if (XMLP_ret::XML_OK == fillDataNode(p_root, *participant_node, profiles_base_name, set_flags)) {
        rootNode.addChild(std::move(participant_node));
        return XMLProfileManagerPart::extractParticipantProfile(rootNode.getChildren().back(), profile_lib_name,
                                                                set_flags);
    } else {
        elogError(XMLPARSER, RetCode_t::RETCODE_ERROR, "Error parsing participant profile");
        ret = XMLP_ret::XML_ERROR;
    }

    return ret;
}

template <typename T>
void XMLParserpart::addAllAttributes(tinyxml2::XMLElement* p_profile, DataNode<T>& node) {
    const tinyxml2::XMLAttribute* attrib;
    for (attrib = p_profile->FirstAttribute(); attrib != nullptr; attrib = attrib->Next()) {
        node.addAttribute(attrib->Name(), attrib->Value());
    }
}

XMLP_ret XMLParserpart::fillDataNode(tinyxml2::XMLElement* p_profile, DataNode<ParticipantAttributes>& participant_node,
                                     const std::string& profiles_base_name, std::vector<bool>& set_flags) {

    if (nullptr == p_profile) {
        elogError(XMLPARSER, RetCode_t::RETCODE_BAD_PARAMETER, "Bad parameters!");
        return XMLP_ret::XML_ERROR;
    }

    const tinyxml2::XMLAttribute* attrib;
    std::string profile_name;
    std::string base_profile_name = profiles_base_name;
    for (attrib = p_profile->FirstAttribute(); attrib != nullptr; attrib = attrib->Next()) {
        if (strcmp(attrib->Name(), xmlString::PROFILE_NAME) == 0) {
            profile_name = attrib->Value();
            continue;
        }

        if (XMLProfileManagerPart::getInheritanceCombinationBaseInfo(attrib->Name())) {  // Participant继承
            base_profile_name = attrib->Value();
            break;
        }
    }

    auto& stored_profiles = XMLProfileManagerPart::participant_profiles_;
    if (stored_profiles.find(profile_name) != stored_profiles.end()) {
        elogError(XMLPARSER, RetCode_t::RETCODE_BAD_PARAMETER,
                  "participant profile '" << profile_name << "' already exist.");
        return XMLP_ret::XML_ERROR;
    }

    if (!base_profile_name.empty()) {
        if (stored_profiles.find(base_profile_name) != stored_profiles.end()) {
            *participant_node.get() = *stored_profiles[base_profile_name].get();
            logDebug(XMLPARSER,
                     "Profile '" << profile_name << "' inherit QOS from profile '" << base_profile_name << "'.");
        } else {
            elogError(XMLPARSER, RetCode_t::RETCODE_BAD_PARAMETER,
                      "Profile '" << profile_name << "'"
                                  << " base Profile '" << base_profile_name << "' not found");
            return XMLP_ret::XML_ERROR;
        }
    }

    addAllAttributes(p_profile, participant_node);

    uint8_t ident = 1U;
    if (XMLP_ret::XML_OK != getXMLParticipantAttributes(p_profile, *participant_node.get(), set_flags, ident)) {
        return XMLP_ret::XML_ERROR;
    }
    return XMLP_ret::XML_OK;
}

XMLP_ret XMLParserpart::parseXMLPublisherProf(tinyxml2::XMLElement* p_root, BaseNode& rootNode,
                                              const std::string& profile_lib_name,
                                              const std::string& profiles_base_name) {
    XMLP_ret ret = XMLP_ret::XML_OK;
    up_publisher_t publisher_atts {new PublisherAttributes};
    up_node_publisher_t publisher_node {new node_publisher_t {NodeType::PUBLISHER, std::move(publisher_atts)}};

    std::vector<bool> set_flags(PublisherConfigKind::PUB_CONFIG_END);
    if (XMLP_ret::XML_OK == fillDataNode(p_root, *publisher_node, profiles_base_name, set_flags)) {
        rootNode.addChild(std::move(publisher_node));
        return XMLProfileManagerPart::extractPublisherProfile(rootNode.getChildren().back(), profile_lib_name,
                                                              set_flags);
    } else {
        elogError(XMLPARSER, RetCode_t::RETCODE_BAD_PARAMETER, "Error parsing publisher profile");
        ret = XMLP_ret::XML_ERROR;
    }
    return ret;
}

XMLP_ret XMLParserpart::fillDataNode(tinyxml2::XMLElement* p_profile, DataNode<PublisherAttributes>& publisher_node,
                                     const std::string& profiles_base_name, std::vector<bool>& set_flags) {
    if (nullptr == p_profile) {
        elogError(XMLPARSER, RetCode_t::RETCODE_BAD_PARAMETER, "Bad parameters!");
        return XMLP_ret::XML_ERROR;
    }

    const tinyxml2::XMLAttribute* attrib;
    std::string profile_name;
    std::string base_profile_name = profiles_base_name;
    for (attrib = p_profile->FirstAttribute(); attrib != nullptr; attrib = attrib->Next()) {
        if (strcmp(attrib->Name(), xmlString::PROFILE_NAME) == 0) {
            profile_name = attrib->Value();
            continue;
        }

        if (XMLProfileManagerPart::getInheritanceCombinationBaseInfo(attrib->Name())) {  // Publisher继承
            base_profile_name = attrib->Value();
            break;
        }
    }

    auto& stored_profiles = XMLProfileManagerPart::publisher_profiles_;
    if (stored_profiles.find(profile_name) != stored_profiles.end()) {
        elogError(XMLPARSER, RetCode_t::RETCODE_BAD_PARAMETER,
                  "data_writer profile '" << profile_name << "' already exist.");
        return XMLP_ret::XML_ERROR;
    }

    if (!base_profile_name.empty()) {
        if (stored_profiles.find(base_profile_name) != stored_profiles.end()) {
            *publisher_node.get() = *stored_profiles[base_profile_name].get();
            logDebug(XMLPARSER,
                     "Profile '" << profile_name << "' inherit QOS from profile '" << base_profile_name << "'.");
        } else {
            elogError(XMLPARSER, RetCode_t::RETCODE_BAD_PARAMETER,
                      "Profile '" << profile_name << "'"
                                  << " base Profile '" << base_profile_name << "' not found");
            return XMLP_ret::XML_ERROR;
        }
    }

    addAllAttributes(p_profile, publisher_node);

    uint8_t ident = 1;
    if (XMLP_ret::XML_OK != getXMLPublisherAttributes(p_profile, *publisher_node.get(), set_flags, ident)) {
        return XMLP_ret::XML_ERROR;
    }

    return XMLP_ret::XML_OK;
}

XMLP_ret XMLParserpart::parseXMLSubscriberProf(tinyxml2::XMLElement* p_root, BaseNode& rootNode,
                                               const std::string& profile_lib_name,
                                               const std::string& profiles_base_name) {
    XMLP_ret ret = XMLP_ret::XML_OK;
    up_subscriber_t subscriber_atts {new SubscriberAttributes};
    up_node_subscriber_t subscriber_node {new node_subscriber_t {NodeType::SUBSCRIBER, std::move(subscriber_atts)}};

    std::vector<bool> set_flags(SubscriberConfigKind::SUB_CONFIG_END);
    if (XMLP_ret::XML_OK == fillDataNode(p_root, *subscriber_node, profiles_base_name, set_flags)) {
        rootNode.addChild(std::move(subscriber_node));
        return XMLProfileManagerPart::extractSubscriberProfile(rootNode.getChildren().back(), profile_lib_name,
                                                               set_flags);
    } else {
        elogError(XMLPARSER, RetCode_t::RETCODE_ERROR, "Error parsing subscriber profile");
        ret = XMLP_ret::XML_ERROR;
    }
    return ret;
}

XMLP_ret XMLParserpart::fillDataNode(tinyxml2::XMLElement* p_profile, DataNode<SubscriberAttributes>& subscriber_node,
                                     const std::string& profiles_base_name, std::vector<bool>& set_flags) {
    if (nullptr == p_profile) {
        elogError(XMLPARSER, RetCode_t::RETCODE_BAD_PARAMETER, "Bad parameters!");
        return XMLP_ret::XML_ERROR;
    }

    const tinyxml2::XMLAttribute* attrib;
    std::string profile_name;
    std::string base_profile_name = profiles_base_name;
    for (attrib = p_profile->FirstAttribute(); attrib != nullptr; attrib = attrib->Next()) {
        if (strcmp(attrib->Name(), xmlString::PROFILE_NAME) == 0) {
            profile_name = attrib->Value();
            continue;
        }

        if (XMLProfileManagerPart::getInheritanceCombinationBaseInfo(attrib->Name())) {  // Subscriber继承
            base_profile_name = attrib->Value();
            break;
        }
    }

    auto& stored_profiles = XMLProfileManagerPart::subscriber_profiles_;
    if (stored_profiles.find(profile_name) != stored_profiles.end()) {
        elogError(XMLPARSER, RetCode_t::RETCODE_BAD_PARAMETER,
                  "data_reader profile '" << profile_name << "' already exist.");
        return XMLP_ret::XML_ERROR;
    }

    if (!base_profile_name.empty()) {
        if (stored_profiles.find(base_profile_name) != stored_profiles.end()) {
            *subscriber_node.get() = *stored_profiles[base_profile_name].get();
            logDebug(XMLPARSER,
                     "Profile '" << profile_name << "' inherit QOS from profile '" << base_profile_name << "'.");
        } else {
            elogError(XMLPARSER, RetCode_t::RETCODE_BAD_PARAMETER,
                      "Profile '" << profile_name << "'"
                                  << " base Profile '" << base_profile_name << "' not found");
            return XMLP_ret::XML_ERROR;
        }
    }
    addAllAttributes(p_profile, subscriber_node);

    uint8_t ident = 1U;
    if (XMLP_ret::XML_OK != getXMLSubscriberAttributes(p_profile, *subscriber_node.get(), set_flags, ident)) {
        elogError(XMLPARSER, RetCode_t::RETCODE_ERROR, "subscriver attr get failed, Profile " << profile_name);
        return XMLP_ret::XML_ERROR;
    }

    return XMLP_ret::XML_OK;
}

XMLP_ret XMLParserpart::parseXMLTopicData(tinyxml2::XMLElement* p_root, BaseNode& rootNode) {
    XMLP_ret ret = XMLP_ret::XML_OK;
    up_topic_t topic_atts {new TopicAttributes};
    up_node_topic_t topic_node {new node_topic_t {NodeType::TOPIC, std::move(topic_atts)}};
    if (XMLP_ret::XML_OK == fillDataNode(p_root, *topic_node)) {
        rootNode.addChild(std::move(topic_node));
        return XMLProfileManagerPart::extractTopicProfile(rootNode.getChildren().back());
    } else {
        elogError(XMLPARSER, RetCode_t::RETCODE_ERROR, "Error parsing topic data node");
        ret = XMLP_ret::XML_ERROR;
    }
    return ret;
}

XMLP_ret XMLParserpart::fillDataNode(tinyxml2::XMLElement* node, DataNode<TopicAttributes>& topic_node) {
    if (nullptr == node) {
        elogError(XMLPARSER, RetCode_t::RETCODE_BAD_PARAMETER, "Bad parameters!");
        return XMLP_ret::XML_ERROR;
    }

    addAllAttributes(node, topic_node);

    uint8_t ident = 1U;
    if (XMLP_ret::XML_OK != getXMLTopicAttributes(node, *topic_node.get(), ident)) {
        return XMLP_ret::XML_ERROR;
    }

    return XMLP_ret::XML_OK;
}

XMLP_ret XMLParserpart::generateProfileByBaseProfile(const std::string& name, const std::string& base_name) {
    auto& stored_part_profiles = XMLProfileManagerPart::participant_profiles_;
    auto& stored_part_set_flags = XMLProfileManagerPart::participant_profile_set_flags_;
    auto& stored_pub_profiles = XMLProfileManagerPart::publisher_profiles_;
    auto& stored_pub_set_flags = XMLProfileManagerPart::publisher_profile_set_flags_;
    auto& stored_sub_profiles = XMLProfileManagerPart::subscriber_profiles_;
    auto& stored_sub_set_flags = XMLProfileManagerPart::subscriber_profile_set_flags_;
    bool has_found = false;

    if (stored_part_profiles.find(base_name) != stored_part_profiles.end()) {
        auto& base_profile = stored_part_profiles[base_name];
        stored_part_profiles[name] = up_participant_t(new ParticipantAttributes(*base_profile.get()));
        stored_part_set_flags[name] = stored_part_set_flags[base_name];
        logDebug(XMLPARSER, "participant profile '" << name << "' inherit from  profile '" << base_name << "'.");
        has_found = true;
    }

    if (stored_pub_profiles.find(base_name) != stored_pub_profiles.end()) {
        auto& base_profile = stored_pub_profiles[base_name];
        stored_pub_profiles[name] = up_publisher_t(new PublisherAttributes(*base_profile.get()));
        stored_pub_set_flags[name] = stored_pub_set_flags[base_name];
        logDebug(XMLPARSER, "data_writer profile '" << name << "' inherit from  profile '" << base_name << "'.");
        has_found = true;
    }

    if (stored_sub_profiles.find(base_name) != stored_sub_profiles.end()) {
        auto& base_profile = stored_sub_profiles[base_name];
        stored_sub_profiles[name] = up_subscriber_t(new SubscriberAttributes(*base_profile.get()));
        stored_sub_set_flags[name] = stored_sub_set_flags[base_name];
        logDebug(XMLPARSER, "data_reader Profile '" << name << "' inherit from  profile '" << base_name << "'.");
        has_found = true;
    }

    if (!has_found) {
        elogError(XMLPARSER, RetCode_t::RETCODE_NO_DATA,
                  "Base profile '" << base_name << "' not found or invalid for profile '" << name << "'.");
        return XMLP_ret::XML_ERROR;
    }
    return XMLP_ret::XML_OK;
}

}  // namespace xmlparser
}  // namespace vbsutil
